﻿using System;
using System.Collections.Generic;
using Library2015;
using System.CodeDom.Compiler;
using System.Linq;
using System.IO;
using System.Reflection;
using System.Windows.Forms;


namespace WaterFall
{
    class MyAdapter:MarshalByRefObject
    {
        string[] refAssemblies;

        public CompilerResults CompileAssembly(String source)
        {
            var clrPath = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory();
            refAssemblies = new string[]
            {
                clrPath + "System.dll",
                clrPath + "System.Core.dll",
                clrPath + "Microsoft.CSharp.dll",
                @"D:\Documents\My Web Sites\AppCommunity\UI\bin\Resources\Library2015.dll"
            };

            // Select the code provider based on the input file extension.
            var provider = CodeDomProvider.CreateProvider("CSharp") ;


            var cp = new CompilerParameters
            {
                //GenerateExecutable = true,
                GenerateInMemory = true,
                TreatWarningsAsErrors = false
            };

            cp.ReferencedAssemblies.AddRange(refAssemblies);

            // Invoke compilation of the source code.
            CompilerResults cr = provider.CompileAssemblyFromSource(cp, source);
            //CopyAssembly();
            return cr;
        }

        void CopyAssembly()
        {
            foreach (var item in refAssemblies.Where(a => !a.Contains("System")))
            {
                var filename = Path.Combine(Environment.CurrentDirectory, Path.GetFileName(item));

                if (File.Exists(filename))
                {
                    if (File.GetLastWriteTime(filename) != File.GetLastWriteTime(filename))
                        File.Copy(item, filename);
                }
                else File.Copy(item, filename);
            }
        }

        public void Run(string source)
        {
            var ass = this.CompileAssembly(source).CompiledAssembly;

            #region Parameters
            var options = ass.CreateInstance("WaterFall.SortOptions") as AppStartOptions;

            options.Parameters[0].SetValue(ass.CreateInstance("WaterFall.SortRuntimeOptions"));

            var sortMethodType = ass.GetType("WaterFall.SortMethod");
            var listType = Type.GetType("System.Collections.Generic.List`1").MakeGenericType(sortMethodType);
            var list = Activator.CreateInstance(listType) as System.Collections.IList;

            var m1 = Enum.ToObject(sortMethodType, 6);
            var m2 = Enum.ToObject(sortMethodType, 6);
            var m3 = Enum.ToObject(sortMethodType, 7);
            list.Add(m1);
            list.Add(m2);
            list.Add(m3);

            options.Parameters[1].SetValue(list);
            options.Parameters[1].ValueParameters[0][0].SetValue(false);
            options.Parameters[1].ValueParameters[1][0].SetValue(true);


            #endregion

            var entry = ass.GetTypes().Select(t => t.GetMethod("Main", BindingFlags.Static | BindingFlags.NonPublic))
    .Single(m => m != null);

            PromptInput(options);
           
            entry.Invoke(null, new object[] { options });
        }

        #region Test
        
        void PromptInput(AppStartOptions options)
        {
            var sb = new System.Text.StringBuilder();
            sb.Append("<html><body>");

            foreach (var item in options.Parameters)
            {
                var valueType = item.GetType().GetGenericArguments()[0];
                sb.Append("<div>");
                if (valueType.IsPrimitive)
                {
                    WritePrimitive(sb, item.Name, valueType);
                }
                else if (valueType.IsEnum)
                {
                    sb.AppendFormat("<span>{0}:</span>", item.Name);

                    var values = Enum.GetValues(valueType);

                    sb.Append("<select>");
                    for (int i = 0; i < values.Length; i++)
                    {
                        sb.AppendFormat("<option value='{1}'>{0}</option>", values.GetValue(i), i);
                    }
                    sb.Append("<select>");

                    sb.AppendFormat("<i>{0}</i>", valueType.Name);
                }
                else
                {
                    sb.AppendFormat("<h3>{0}({1})</h3>", item.Name, valueType.Name);
                    foreach (var p in valueType.GetProperties())
                    {
                        WritePrimitive(sb, p.Name, p.PropertyType);
                    }
                }

                sb.Append("</div>");
            }

            sb.Append("</body></html>");

            File.WriteAllText("xpmm.htm",sb.ToString());

            PromptForm(sb.ToString());
        }

        private void PromptForm(string content)
        {
            var f = new Form();

            var browser = new WebBrowser()
            {
                Dock = DockStyle.Fill,
                DocumentText = content
            };

            f.Controls.Add(browser);
            f.ShowDialog();
        }

        private static void WritePrimitive(System.Text.StringBuilder sb, string name, Type valueType)
        {
            sb.Append("<p>");
            sb.AppendFormat("<span>{0}:</span>", name);
            sb.AppendFormat("<input />");
            sb.AppendFormat("<i>{0}</i>", valueType.Name);
            sb.Append("</p>");
        }


        #endregion

        public ICreateInputs InputsProvider { get; set; }
    }

    public interface ICreateInputs
    {
        void CreatePrimitive<T>();



    }



    public class Down
    {
        [STAThread]
        static void Main()
        {
            var domain = AppDomain.CreateDomain("wow");
            domain.SetupInformation.ShadowCopyFiles = "True";

            var type = typeof(MyAdapter);
            var adapter = domain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName) as MyAdapter;

            var filename = @"D:\Documents\My Web Sites\AppCommunity\UI\bin\Resources\Samples\AppParameterTest.cs";
            var content = File.ReadAllText(filename);

            adapter.Run(content);

            Console.ReadLine();

        }
    }


}
